from typing import Dict


def new_board() -> Dict[int, str]:
    """
    使用字典在Python中存储棋盘，
    因为我们不包括给定范围内的所有数字。
    """
    return {
        13: "!",
        14: "!",
        15: "!",
        22: "!",
        23: "!",
        24: "!",
        29: "!",
        30: "!",
        31: "!",
        32: "!",
        33: "!",
        34: "!",
        35: "!",
        38: "!",
        39: "!",
        40: "!",
        42: "!",
        43: "!",
        44: "!",
        47: "!",
        48: "!",
        49: "!",
        50: "!",
        51: "!",
        52: "!",
        53: "!",
        58: "!",
        59: "!",
        60: "!",
        67: "!",
        68: "!",
        69: "!",
        41: "O",
    }


def print_instructions() -> None:
    print(
        """
这是棋盘：

          !    !    !
         13   14   15

          !    !    !
         22   23   24

!    !    !    !    !    !    !
29   30   31   32   33   34   35

!    !    !    !    !    !    !
38   39   40   41   42   43   44

!    !    !    !    !    !    !
47   48   49   50   51   52   53

          !    !    !
         58   59   60

          !    !    !
         67   68   69

为了节省打字时间，游戏过程中将使用压缩版本的棋盘。
请参考上面的棋盘进行跳棋。好的，让我们开始。
    """
    )


def print_board(board: Dict[int, str]) -> None:
    """使用传入参数中的索引打印棋盘"""
    print(" " * 2 + board[13] + board[14] + board[15])
    print(" " * 2 + board[22] + board[23] + board[24])
    print(
        board[29]
        + board[30]
        + board[31]
        + board[32]
        + board[33]
        + board[34]
        + board[35]
    )
    print(
        board[38]
        + board[39]
        + board[40]
        + board[41]
        + board[42]
        + board[43]
        + board[44]
    )
    print(
        board[47]
        + board[48]
        + board[49]
        + board[50]
        + board[51]
        + board[52]
        + board[53]
    )
    print(" " * 2 + board[58] + board[59] + board[60])
    print(" " * 2 + board[67] + board[68] + board[69])


def play_game() -> None:
    # 创建新棋盘
    board = new_board()

    # 主游戏循环
    while not is_game_finished(board):
        print_board(board)
        while not move(board):
            print("非法移动！请重试")

    peg_count = sum(1 for key in board.keys() if board[key] == "!")
    print(f"你剩下 {str(peg_count)} 个棋子")

    if peg_count == 1:
        print("太棒了！你得了满分！")
        print("请保存这张纸作为你的成就记录！")


def move(board: Dict[int, str]) -> bool:
    """查询用户移动。如果用户输入无效或移动失败，返回false，如果移动成功，返回true"""
    # 要求用户输入起始跳动的棋子位置
    start = input("请输入起始位置：")

    # 如果输入的数据不是数字，return false
    if not start.isdigit():
        return False

    # 把用户输入转换数字
    start = int(start)

    # 如果起始位置不在棋盘上或者起始位置不是！（棋子） 返回false
    if start not in board or board[start] != "!":
        return False

    # 要求用户输入一个结束位置
    end = input("请输入结束位置：")
    # 如果用户输入的数据不是数字，返回false
    if not end.isdigit():
        return False

    # 把用户输入的内容转数字
    end = int(end)

    # 如果如果结束位置不在棋盘上或者结束位置不是O（空缺） 返回false
    if end not in board or board[end] != "O":
        return False

    # 找到中间的棋子在字典里面的位置并且将其替换为O
    for i in range(1, 9):  # 检查所有可能的跳跃距离
        jump = start + i if start < end else start - i
        if jump in board and board[jump] == "!":
            next_jump = jump + i if start < end else jump - i
            if next_jump == end:
                board[jump] = "O"  # 将中间的棋子移动到空位
                board[start] = "O"  # 将起始位置的棋子移动到空位
                board[end] = "!"  # 将结束位置的棋子更新为起始位置的棋子
                return True
    return False


def main() -> None:
    print(" " * 33 + "H-I-Q")
    print(" " * 15 + "创意计算 莫里斯敦，新泽西")
    print_instructions()
    play_game()


def is_game_finished(board) -> bool:
    """检查所有位置，看是否有可能在该位置移动。"""
    for pos in board.keys():
        if board[pos] == "!":
            for space in [1, 9]:
                # 检查下一个位置是否有棋子
                next_to_peg = ((pos + space) in board) and board[pos + space] == "!"
                # 检查向前（+位置）或向后（-位置）的移动空间
                has_movable_space = (
                        pos - space not in board
                        or board[pos - space] != "!"
                        or pos + space * 2 not in board
                        or board[pos + space * 2] != "O"
                )
                if next_to_peg and has_movable_space:
                    return False
    return True


if __name__ == "__main__":
    main()